#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "ir_Midea.h"
#include "IRutils.h"
#include "driver/rmt_tx.h"
#include "ir_air_conditioner.h"

// Midea R05D协议头尾符号数
#define MIDEA_R05D_HEAD_SYMBOLS      2 * 2
#define MIDEA_R05D_SEPARATOR_SYMBOLS 2
#define MIDEA_R05D_TAIL_SYMBOLS      1
#define MIDEA_R05D_TOTAL_SYMBOLS     (MIDEA_R05D_HEAD_SYMBOLS + MIDEA_R05D_SEPARATOR_SYMBOLS + 2 * kMideaR05DBits + MIDEA_R05D_TAIL_SYMBOLS)

static rmt_symbol_word_t *out_symbols = NULL;

/*温度对应数据表*/
static uint8_t temp_data_table[] = {
    0x00, //17
    0x01, //18
    0x03, //19
    0x02, //20
    0x06, //21
    0x07, //22
    0x05, //23
    0x04, //24
    0x0C, //25
    0x0D, //26
    0x09, //27
    0x08, //28
    0x0a, //29
    0x0B, //30
};

typedef struct {
    Air_conditioner_t ac;
    union MideaR05DProtocol r05d;
} MideaR05D_t, *pMideaR05D_t;
static uint8_t midea_r05d_get_power(pAir_conditioner_t pAC);
/**
 * @brief 获取当前设置的温度
 * @param pAC 空调设备指针
 * @return 当前温度值（摄氏度）
 */
static uint8_t midea_r05d_get_temp(pAir_conditioner_t pAC)
{
    if (!pAC)
        return kMideaR05DDefTempC;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;
    uint8_t temp = (uint8_t)pMidea->r05d.C.Temp;
    // 温度计算：实际温度 = Temp值 + 17（根据协议定义）
    int i = 0;
    for (; i < sizeof(temp_data_table); i++) {
        if (temp_data_table[i] == temp) {
            break;
        }
    }
    ESP_LOGE("dubug", "temp_data_table[%d]=%d,temp=%d", i, temp_data_table[i], temp);
    return i + kMideaR05DMinTempC;
}

/**
 * @brief 设置温度
 * @param pAC 空调设备指针
 * @param degrees 目标温度（摄氏度）
 * @return 实际设置的温度值
 */
static uint8_t midea_r05d_set_temp(pAir_conditioner_t pAC, const uint8_t degrees)
{
    if ((!pAC) || (!midea_r05d_get_power(pAC)))
        return 0;

    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;

    // 温度范围限制
    uint8_t temp = degrees;
    if (temp < kMideaR05DMinTempC)
        temp = kMideaR05DMinTempC;
    else if (temp > kMideaR05DMaxTempC)
        temp = kMideaR05DMaxTempC;

    // 计算温度编码（Temp = 实际温度 - 17）
    pMidea->r05d.C.Temp = temp_data_table[temp - kMideaR05DMinTempC];
    // 更新反码
    pMidea->r05d.C_inv = ~pMidea->r05d.raw[4] & 0xFF;

    return midea_r05d_get_temp(pAC);
}

/**
 * @brief 电源控制
 * @param pAC 空调设备指针
 * @param on 1=开机, 0=关机
 * @return 当前电源状态
 */
static uint8_t midea_r05d_set_power(pAir_conditioner_t pAC, const uint8_t on)
{
    if (!pAC)
        return 0;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;

    if (on) {
        // 开机状态：恢复正常编码格式（保持原有设置）
        pMidea->r05d.A = 0xB2; // 标准识别码
        pMidea->r05d.A_inv = ~pMidea->r05d.A & 0xFF;
    } else {
        // 关机状态：使用固定编码
        pMidea->r05d.A = 0xB2;
        pMidea->r05d.A_inv = ~pMidea->r05d.A & 0xFF;
        pMidea->r05d.raw[2] = kMideaR05DOffCodeB;
        pMidea->r05d.B_inv = ~kMideaR05DOffCodeB & 0xFF;
        pMidea->r05d.raw[4] = kMideaR05DOffCodeC;
        pMidea->r05d.C_inv = ~kMideaR05DOffCodeC & 0xFF;
    }

    return ESP_OK;
}

/**
 * @brief 获取当前电源状态
 * @param pAC 空调设备指针
 * @return 1=开机, 0=关机
 */
static uint8_t midea_r05d_get_power(pAir_conditioner_t pAC)
{
    if (!pAC)
        return 0;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;
    // 通过C字段判断是否为关机状态
    return (pMidea->r05d.raw[4] == kMideaR05DOffCodeC) ? 0 : 1;
}

/**
 * @brief 设置运行模式
 * @param pAC 空调设备指针
 * @param mode 运行模式（kMideaAc*）
 * @return 实际设置的模式
 */
static uint8_t midea_r05d_set_mode(pAir_conditioner_t pAC, const uint8_t mode)
{
    if (!pAC || !midea_r05d_get_power(pAC))
        return kMideaAcAuto;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;
    // 验证模式有效性
    uint8_t new_mode;
    switch (mode) {
        case AcModeAuto:
            new_mode = kMideaAcAuto;
            break;
        case AcModeCool:
            new_mode = kMideaAcCool;
            break;
        case AcModeDry:
            new_mode = kMideaAcDry;
            break;
        case AcModeHeat:
            new_mode = kMideaAcHeat;
            break;
        case AcModeFan:
            new_mode = kMideaAcFan;
            break;
        default:
            new_mode = kMideaAcAuto;
            break;
    }

    pMidea->r05d.C.Mode = new_mode;
    pMidea->r05d.C_inv = ~pMidea->r05d.raw[4] & 0xFF;
    return new_mode;
}

/**
 * @brief 获取当前运行模式
 * @param pAC 空调设备指针
 * @return 当前模式
 */
static uint8_t midea_r05d_get_mode(pAir_conditioner_t pAC)
{
    if (!pAC)
        return kMideaAcAuto;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;
    uint8_t pri_mode = pMidea->r05d.C.Mode;

    // 验证模式有效性
    uint8_t new_mode;
    switch (pri_mode) {
        case kMideaAcAuto:
            new_mode = AcModeAuto;
            break;
        case kMideaAcCool:
            new_mode = AcModeCool;
            break;
        case kMideaAcDry:
            new_mode = AcModeDry;
            break;
        case kMideaAcHeat:
            new_mode = AcModeHeat;
            break;
        // case kMideaAcFan:
        //     new_mode = AcModeFan;
        //     break;
        default:
            new_mode = AcModeAuto;
            break;
    }
    return new_mode;
}

/**
 * @brief 设置风速
 * @param pAC 空调设备指针
 * @param speed 风速（kMideaAcFan*）
 * @return 实际设置的风速
 */
static uint8_t midea_r05d_set_fan(pAir_conditioner_t pAC, const uint8_t speed)
{
    if (!pAC || !midea_r05d_get_power(pAC))
        return kMideaAcFanAuto;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;

    // 验证风速有效性
    switch (speed) {
        case AcFanAuto:
            pMidea->r05d.B.Fan = kMideaAcFanAuto;
            break;
        case AcFanLow:
            pMidea->r05d.B.Fan = kMideaAcFanLow;
            break;
        case AcFanMed:
            pMidea->r05d.B.Fan = kMideaAcFanMed;
            break;
        case AcFanHigh:
            pMidea->r05d.B.Fan = kMideaAcFanHigh;
            break;
        default:
            pMidea->r05d.B.Fan = kMideaAcFanFixed;
            break;
    }

    // 确保固定位为0x1F
    pMidea->r05d.B.Fixed = 0x1F;
    // 更新B字段原始值及反码
    pMidea->r05d.raw[2] = (pMidea->r05d.B.Fan << 5) | pMidea->r05d.B.Fixed;
    pMidea->r05d.B_inv = ~pMidea->r05d.raw[2] & 0xFF;
    return speed;
}

/**
 * @brief 获取当前风速
 * @param pAC 空调设备指针
 * @return 当前风速
 */
static uint8_t midea_r05d_get_fan(pAir_conditioner_t pAC)
{
    if (!pAC)
        return kMideaAcFanAuto;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;
    uint8_t speed = pMidea->r05d.B.Fan;
    uint8_t ret_speed;
    // 验证风速有效性
    switch (speed) {
        case kMideaAcFanAuto:
            ret_speed = AcFanAuto;
            break;
        case kMideaAcFanLow:
            ret_speed = AcFanLow;
            break;
        case kMideaAcFanMed:
            ret_speed = AcFanMed;
            break;
        case kMideaAcFanHigh:
            ret_speed = AcFanHigh;
            break;
        default:
            ret_speed = AcFanAuto;
            break;
    }

    return ret_speed;
}

/**
 * @brief 扩展功能（Midea R05D协议暂不支持）
 * @param pAC 空调设备指针
 * @param extend 扩展功能标识
 * @param data 功能数据
 * @return 0（不支持）
 */
static uint8_t midea_r05d_set_extend(pAir_conditioner_t pAC, const uint8_t extend, uint8_t data)
{
    return 0; // 暂不支持扩展功能
}

/**
 * @brief 获取扩展功能状态（Midea R05D协议暂不支持）
 * @param pAC 空调设备指针
 * @return 0
 */
static uint8_t midea_r05d_get_extend(pAir_conditioner_t pAC)
{
    return 0;
}

/**
 * @brief 生成RMT符号数据
 * @param pAC 空调设备指针
 * @param len 输出符号长度
 * @return RMT符号数组
 */
static rmt_symbol_word_t *midea_r05d_send(pAir_conditioner_t pAC, size_t *len)
{
    if (!pAC || !len)
        return NULL;
    pMideaR05D_t pMidea = (pMideaR05D_t)pAC;
    size_t cnt = 0;
    int i = 0;
    ESP_LOGI("debud", "A:%02X,~A:%02X, B:%02X,~B:%02X, C:%02X,~C:%02X", pMidea->r05d.raw[0], pMidea->r05d.raw[1], pMidea->r05d.raw[2], pMidea->r05d.raw[3], pMidea->r05d.raw[4], pMidea->r05d.raw[5]);

    // 头部符号：4500us高 + 4500us低
    out_symbols[cnt].duration0 = 3000;
    out_symbols[cnt].level0 = 1;
    out_symbols[cnt].duration1 = 1500;
    out_symbols[cnt].level1 = 1;
    cnt++;
    out_symbols[cnt].duration0 = 3000;
    out_symbols[cnt].level0 = 0;
    out_symbols[cnt].duration1 = 1500;
    out_symbols[cnt].level1 = 0;
    cnt++;

    // 数据位编码：
    // 逻辑0：560us高 + 560us低
    // 逻辑1：560us高 + 1690us低
    for (i = 0; i < kMideaR05DStateLength; i++) {
        uint8_t byte = pMidea->r05d.raw[i];
        for (int bit = 7; bit >= 0; bit--) { // MSB优先
            bool is_set = (byte >> bit) & 1;
            out_symbols[cnt].level0 = 1;
            out_symbols[cnt].duration0 = MideaR05_0_DHIGH_US;
            out_symbols[cnt].level1 = 0;
            out_symbols[cnt].duration1 = is_set ? MideaR05_1_LOW_US : MideaR05_0_LOW_US;
            cnt++;
        }
    }
    //分隔码 550us高电平+5.22ms=5220低电平
    out_symbols[cnt].duration0 = 550;
    out_symbols[cnt].level0 = 1;
    out_symbols[cnt].duration1 = 220;
    out_symbols[cnt].level1 = 0;
    cnt++;
    out_symbols[cnt].duration0 = 3000;
    out_symbols[cnt].level0 = 0;
    out_symbols[cnt].duration1 = 2000;
    out_symbols[cnt].level1 = 0;
    cnt++;
    // 头部符号：4500us高 + 4500us低
    out_symbols[cnt].duration0 = 3000;
    out_symbols[cnt].level0 = 1;
    out_symbols[cnt].duration1 = 1500;
    out_symbols[cnt].level1 = 1;
    cnt++;
    out_symbols[cnt].duration0 = 3000;
    out_symbols[cnt].level0 = 0;
    out_symbols[cnt].duration1 = 1500;
    out_symbols[cnt].level1 = 0;
    cnt++;

    // 数据位编码：
    // 逻辑0：560us高 + 560us低
    // 逻辑1：560us高 + 1690us低
    for (i = 0; i < kMideaR05DStateLength; i++) {
        uint8_t byte = pMidea->r05d.raw[i];
        for (int bit = 7; bit >= 0; bit--) { // MSB优先
            bool is_set = (byte >> bit) & 1;
            out_symbols[cnt].level0 = 1;
            out_symbols[cnt].duration0 = MideaR05_0_DHIGH_US;
            out_symbols[cnt].level1 = 0;
            out_symbols[cnt].duration1 = is_set ? MideaR05_1_LOW_US : MideaR05_0_LOW_US;
            cnt++;
        }
    }

    // 结束符号：560us高
    out_symbols[cnt].duration0 = 560;
    out_symbols[cnt].level0 = 1;
    out_symbols[cnt].duration1 = 0;
    out_symbols[cnt].level1 = 0;
    cnt++;
    *len = cnt;
    return out_symbols;
}

/**
 * @brief 释放资源
 * @param pAC 空调设备指针
 */
static void midea_r05d_del(pAir_conditioner_t pAC)
{
    if (pAC)
        free(pAC);
    if (out_symbols) {
        free(out_symbols);
        out_symbols = NULL;
    }
}

/**
 * @brief 初始化Midea R05D空调控制器
 * @return 空调设备指针
 */
pAir_conditioner_t midea_r05d_init(void)
{
    pMideaR05D_t midea = (pMideaR05D_t)malloc(sizeof(MideaR05D_t));
    if (!midea)
        return NULL;

    // 初始化接口函数
    midea->ac.ir_protocol = MIDEA_R05D_PROTOCOL; // 需要在头文件中定义
    midea->ac.set_temp = midea_r05d_set_temp;
    midea->ac.get_temp = midea_r05d_get_temp;
    midea->ac.set_power = midea_r05d_set_power;
    midea->ac.get_power = midea_r05d_get_power;
    midea->ac.set_mode = midea_r05d_set_mode;
    midea->ac.get_mode = midea_r05d_get_mode;
    midea->ac.set_fan = midea_r05d_set_fan;
    midea->ac.get_fan = midea_r05d_get_fan;
    midea->ac.set_extend = midea_r05d_set_extend;
    midea->ac.get_extend = midea_r05d_get_extend;
    midea->ac.send = midea_r05d_send;
    midea->ac.del = midea_r05d_del;

    // 初始化协议数据
    midea->r05d.A = kMideaR05DCodeA;
    midea->r05d.A_inv = ~midea->r05d.raw[0] & 0xFF;
    midea->r05d.B.Fixed = 0x1F;
    midea->r05d.B.Fan = kMideaAcFanAuto;
    midea->r05d.B_inv = ~midea->r05d.raw[2] & 0xFF;
    midea->r05d.C.Fixed = 0x00;
    midea->r05d.C.Mode = kMideaAcAuto;
    midea->r05d.C.Temp = 0x0C; // 25度
    midea->r05d.C_inv = ~midea->r05d.raw[4] & 0xFF;

    // 分配RMT符号内存
    out_symbols = (rmt_symbol_word_t *)malloc(MIDEA_R05D_TOTAL_SYMBOLS * sizeof(rmt_symbol_word_t));
    if (!out_symbols) {
        free(midea);
        return NULL;
    }

    return &midea->ac;
}